package com.netease.nie.service;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.netease.nie.base.cache.CacheParam;
import com.netease.nie.base.cache.DataOperation;
import com.netease.nie.base.cache.redis.Redis;
import com.netease.nie.base.cache.redis.RedisManager;
import com.netease.nie.base.exceptions.BusinessException;
import com.netease.nie.base.utils.ConvertUtils;
import com.netease.nie.base.utils.CopyUtils;
import com.netease.nie.config.CreditGradeProperties;
import com.netease.nie.constants.BusinessConstants;
import com.netease.nie.constants.CachePrefixConstants;
import com.netease.nie.dao.CreditDao;
import com.netease.nie.dao.OrdersDao;
import com.netease.nie.dao.UserDao;
import com.netease.nie.dto.CreditInHomePageDto;
import com.netease.nie.dto.CreditInJFMallDto;
import com.netease.nie.dto.CreditInUserInfoDto;
import com.netease.nie.model.Credit;
import com.netease.nie.model.User;

/**
 * 
 * @author wwbn3695
 * @createDate July 1st,2016
 * 
 */
@Service
public class CreditServiceImpl implements CreditService {

	private static final String USER_CREDIT_PREFIX = CachePrefixConstants.UserPrefix.USER_CREDIT_PREFIX;
	private static final String USER_INFO_PREFIX = CachePrefixConstants.UserPrefix.USER_INFO_PREFIX;
	
	@Autowired
	private CreditDao creditDao;

	@Autowired
	private OrdersDao orderDao;
	
	@Autowired
	private UserDao userDao;
	
	@Autowired
	private Redis redis;

	@Autowired
	private CreditGradeProperties creditGradeProperties;
	
	public CreditInHomePageDto queryCreditInHomePageDtoByUserId(long userId) {
		Credit credit = queryUserCreditByUserId(userId);
		if (credit == null)
			return null;
		
		CreditInHomePageDto creditInHomePageDto = new CreditInHomePageDto();
		CopyUtils.copy(creditInHomePageDto, credit);
		creditInHomePageDto.setId(credit.getUserId());
		
		//获取下一等级所需积分
		Integer currentLevel = credit.getLevel();
		Integer nextLevelCredit = getNextLevelCredit(currentLevel);
		creditInHomePageDto.setNextLevelCredit(nextLevelCredit);
		
		//查询用户昵称
		RedisManager redisManager = buildRedisManager(userId);
		User user = (User) redisManager.passiveOperateCache(User.class);
		String nickname = user.getNickName();
		creditInHomePageDto.setNickname(nickname);
				
		int exchangeCountByUserId = orderDao.getExchangeCountByUserId(userId);	//查询我的兑换数目
		creditInHomePageDto.setMyExchangeCount(exchangeCountByUserId);
		
		return creditInHomePageDto;
	}
	
	public CreditInJFMallDto queryCreditInJFMallDtoByUserId(long userId) {
		Credit credit = queryUserCreditByUserId(userId);
		if (credit == null)
			return null;
		CreditInJFMallDto creditInJFMallDto = new CreditInJFMallDto();
		CopyUtils.copy(creditInJFMallDto, credit);
		creditInJFMallDto.setId(credit.getUserId());
		return creditInJFMallDto;
	}
	
	public CreditInUserInfoDto queryCreditInUserInfoDtoByUserId(long userId) {
		Credit credit = queryUserCreditByUserId(userId);
		if (credit == null)
			return null;
		CreditInUserInfoDto creditInUserInfoDto = new CreditInUserInfoDto();
		CopyUtils.copy(creditInUserInfoDto, credit);
		creditInUserInfoDto.setId(credit.getUserId());
		
		//获取下一等级所需积分
		Integer currentLevel = credit.getLevel();
		Integer nextLevelCredit = getNextLevelCredit(currentLevel);
		creditInUserInfoDto.setNextLevelCredit(nextLevelCredit);
		
		//查询用户昵称
		RedisManager redisManager = buildRedisManager(userId);
		User user = (User) redisManager.passiveOperateCache(User.class);
		String nickname = user.getNickName();
		creditInUserInfoDto.setNickname(nickname);
		
		return creditInUserInfoDto;
	}

	public int queryUserCreditLevelByUserId(long userId) {
		String userCreditKey = USER_CREDIT_PREFIX + userId;
		int level = 0;
		String levelStr = redis.hget(userCreditKey, "level");
		if (StringUtils.isNotBlank(levelStr)) {
			level = Integer.valueOf(levelStr);
		} else {
			Credit credit = queryUserCreditByUserId(userId);
			level = credit.getLevel();
		}
		return level;
	}

	public Long insertUserCredit(Credit credit) throws Exception {
		return creditDao.insertUserCredit(credit);
	}

	public Credit queryUserCreditByUserId(long userId) {
		String userCreditKey = USER_CREDIT_PREFIX + userId;
		boolean exists = redis.exists(userCreditKey);
		Credit credit = null;
		if (!exists) {
			credit = creditDao.forceQueryUserCreditByUserId(userId);
			if (credit != null) {
				try {
					Map<String, String> map = (Map<String, String>) ConvertUtils.javaBean2StringValueMap(credit);
					redis.hmset(userCreditKey, map);
					redis.expire(userCreditKey, 3600);
				} catch (IllegalAccessException | IllegalArgumentException
						| InvocationTargetException | IntrospectionException e) {
					// e.printStackTrace();
				}
			}
		} else {
			try {
				String[] fields = ConvertUtils
						.getJavaBeanProperties(Credit.class);
				if (fields != null) {
					Map<String, String> map = new HashMap<String, String>();
					List<String> strList = redis.hmget(userCreditKey, fields);
					if (strList != null && !strList.isEmpty()) {
						int fieldsLen = fields.length;
						String text = null;
						for (int i = 0; i < fieldsLen; i++) {
							text = strList.get(i);
							map.put(fields[i], text);
						}
						credit = (Credit) ConvertUtils.map2JavaBean(Credit.class,
								map);
					}
				}
			} catch (InstantiationException | IllegalAccessException
					| IntrospectionException | InvocationTargetException e) {
				// e.printStackTrace();
			}
		}
		return credit;
	}
	
	/**
	 * 根据当前等级获取下一级所需积分
	 * @param currentLevel
	 * @return
	 */
	private Integer getNextLevelCredit(Integer currentLevel) {
		List<Integer> levelRange = creditGradeProperties.getLevelRange(currentLevel);	//格式为上下限[X,Y]
		return levelRange.get(1); //返回上限
	}
	
	private RedisManager buildRedisManager(final Long userId) {
		DataOperation dataOperation = new DataOperation() {	//如果缓存没有，则需要去数据库取数据
			public Object operate() {
				User user = userDao.queryUserInfoByUserId(userId);
				if (user == null)
					throw new BusinessException(BusinessConstants.USER_NOT_EXISTS.getCode(),
							BusinessConstants.USER_NOT_EXISTS.getMsg());
				return user;
			}
		};
		String userInfoKey = USER_INFO_PREFIX + userId;
		List<String> keyList = new ArrayList<>();
		keyList.add(userInfoKey);
		CacheParam cacheParam = new CacheParam();
		cacheParam.setKeyList(keyList);
		cacheParam.setPrefix(USER_INFO_PREFIX);
		try {
			String[] fields = ConvertUtils
					.getJavaBeanProperties(User.class);
			cacheParam.setHashFields(fields);
		} catch (InstantiationException | IllegalAccessException | IntrospectionException e) {
			
		}

		return new RedisManager(cacheParam, dataOperation);
	}

	public void reloadUserCredit(long userId) {
		String userCreditKey = USER_CREDIT_PREFIX + userId;
		redis.del(userCreditKey);
	}
	
	public int deductUserCredit(Credit credit) {
		try {
			return creditDao.deductUserCredit(credit);
		} catch (Exception e) {
			return 0;
		}
	}

	public int addUserCredit(Credit credit) {
		try {
			return creditDao.addUserCredit(credit);
		} catch (Exception e) {
			return 0;
		}
	}

	@Override
	public int deductAndAddUserCredit(Credit credit) {
		try {
			return creditDao.deductAndAddUserCredit(credit);
		} catch (Exception e) {
			return 0;
		}
	}


}
